#pragma once
#include "ir.h"
#include "live_var.h"
#include <vector>
#include <map>
#include <set>
#include <string>

namespace reg_alloc
{
    /* 函数调用约定相关工作 */
    // 由于依赖寄存器分配的中间结果，以下函数调用约定的工作在寄存器分配阶段完成：
    // 1. 保存与恢复caller saved寄存器
    // 2. 传递被调用者所需的参数

    struct LiveInterval
    {
        int start;
        int end;
        bool crosses_call;
        bool allocated;
        int reg_index;
        int spill_index;
    };

    class RegAllocator
    {
    public:
        ir::Function Allocate(ir::Function& func);
    private:
        // 寄存器分配的主要步骤
        void ComputeStartEnd(ir::Function& func, 
            live_var::FuncLiveness& func_liveness);
        void ComputeCallSite(ir::Function& func);
        void ComputeCrossesCall();
        void LinearScan();  
        void ComputeCallSiteUsedReg();
        void ReplaceVar(ir::Function& func);
        void AllocCallerSavedSlot(ir::Function& func);
        void StoreLoadCallerSaved(ir::Function& func);     
        void AllocArgSlot(ir::Function& func);
        void PassArg(ir::Function& func);
        
        // 其他辅助函数
        void ExpireInterval(int instr_index);
        void ReplaceInstrSrc(
            ir::Instruction& instr, std::vector<ir::Instruction>& load_instrs);
        void ReplaceInstrDest(
            ir::Instruction& instr, std::vector<ir::Instruction>& store_instrs, 
            std::vector<ir::Instruction>& alloc_instrs);  
        void StoreLoadInstrCallerSaved(
            std::vector<bool>& call_site_used_regs, 
            std::vector<ir::Instruction>& store_instrs, 
            std::vector<ir::Instruction>& load_instrs);
        void PassInstrArg(
            ir::Instruction& instr, std::vector<ir::Instruction>& new_instrs);
        void PassInstrExtraArg(
            ir::Instruction& instr, std::vector<ir::Instruction>& new_instrs);

        std::vector<LiveInterval> live_intervals;
        std::set<LiveInterval*, bool(*)(LiveInterval*, LiveInterval*)> 
            active_intervals;
        std::vector<bool> used_regs;
        std::vector<int> call_sites;
        std::vector<std::vector<bool>> call_sites_used_regs;
        std::map<std::string, int> var_index_map;
    };
}